package com.zw.dao.impl;

import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.zw.dao.ElasticSearchDao;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import com.zw.es.InitElasticSearchConfig;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.params.SearchType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
//import org.apache.lucene.queryparser.xml.FilterBuilder;
import org.codehaus.jettison.json.JSONObject;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
//import org.elasticsearch.index.query.functionscore.factor.FactorBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.builder.SearchSourceBuilder;
//import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
//import org.elasticsearch.search.facet.FacetBuilders;
import org.elasticsearch.search.collapse.CollapseBuilder;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;


import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import io.searchbox.client.JestResult;
import io.searchbox.cluster.Health;
import io.searchbox.cluster.NodesInfo;
import io.searchbox.cluster.NodesStats;
import io.searchbox.core.Bulk;
import io.searchbox.core.Delete;
import io.searchbox.core.Get;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import io.searchbox.core.SearchResult.Hit;
import io.searchbox.core.Suggest;
import io.searchbox.core.SuggestResult;
import io.searchbox.core.SuggestResult.Suggestion;
import io.searchbox.core.Update;
import io.searchbox.indices.ClearCache;
import io.searchbox.indices.CloseIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.Flush;
import io.searchbox.indices.IndicesExists;
import io.searchbox.indices.Optimize;
/**
 * Created by Zw on 2018/3/9.
 */
@Component
public class ElasticSearchDaoImpl implements ElasticSearchDao {

     public static final Log log = LogFactory.getLog(ElasticSearchDaoImpl.class);

    @Autowired
    private InitElasticSearchConfig esConfig ;


    public JestResult deleteIndex(String type) {
        DeleteIndex deleteIndex = new DeleteIndex.Builder(type).build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(deleteIndex);
            log.info("deleteIndex == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult clearCache() {
        ClearCache closeIndex = new ClearCache.Builder().build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(closeIndex);
            log.info("clearCache == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult closeIndex(String type) {
        CloseIndex closeIndex = new CloseIndex.Builder(type).build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(closeIndex);
            log.info("closeIndex == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult optimizeIndex() {
        Optimize optimize = new Optimize.Builder().build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(optimize);
            log.info("optimizeIndex == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult flushIndex() {
        Flush flush = new Flush.Builder().build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(flush);
            log.info("flushIndex == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult indicesExists() {
        IndicesExists indicesExists = new IndicesExists.Builder("article").build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(indicesExists);
            log.info("indicesExists == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult nodesInfo() {
        NodesInfo nodesInfo = new NodesInfo.Builder().build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(nodesInfo);
            log.info("nodesInfo == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult health() {
        Health health = new Health.Builder().build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(health);
            log.info("health == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult nodesStats() {
        NodesStats nodesStats = new NodesStats.Builder().build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(nodesStats);
            log.info("nodesStats == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult updateDocument(String script , String index, String type, String id) {
        /*String script = "{" +
                "    \"doc\" : {" +
                "        \"title\" : \""+article.getTitle()+"\"," +
                "        \"content\" : \""+article.getContent()+"\"," +
                "        \"author\" : \""+article.getAuthor()+"\"," +
                "        \"source\" : \""+article.getSource()+"\"," +
                "        \"url\" : \""+article.getUrl()+"\"," +
                "        \"pubdate\" : \""+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(article.getPubdate())+"\"" +
                "    }" +
                "}";*/
        Update update = new Update.Builder(script).index(index).type(type).id(id).build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(update);
            log.info("updateDocument == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result ;
    }

    public JestResult deleteDocument(String index, String type, String id) {
        Delete delete = new Delete.Builder(id).index(index).type(type).build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(delete);
            log.info("deleteDocument == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public <T> JestResult getDocument(T object , String index, String type, String id) {
        Get get = new Get.Builder(index, id).type(type).build();
        JestResult result = null ;
        try {
            result = esConfig.getClient().execute(get);
            T o = (T) result.getSourceAsObject(object.getClass());
            for (Method method : o.getClass().getMethods()) {
                log.info("getDocument == " + method.getName());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;

    }

    public List<Suggestion> suggest() {
        String suggestionName = "my-suggestion";
        Suggest suggest = new Suggest.Builder("{" +
                "  \"" + suggestionName + "\" : {" +
                "    \"text\" : \"the amsterdma meetpu\"," +
                "    \"term\" : {" +
                "      \"field\" : \"body\"" +
                "    }" +
                "  }" +
                "}").build();
        SuggestResult suggestResult = null ;
        List<SuggestResult.Suggestion> suggestionList = null ;
        try {
            suggestResult = esConfig.getClient().execute(suggest);
            log.info("suggestResult.isSucceeded() == " + suggestResult.isSucceeded());
            suggestionList = suggestResult.getSuggestions(suggestionName);
            log.info("suggestionList.size() == " + suggestionList.size());
            for(SuggestResult.Suggestion suggestion:suggestionList){
                System.out.println(suggestion.text);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return suggestionList ;
    }

    public <T> List<Hit<T, Void>> searchAll(String index , T o) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(index)
                .build();
        SearchResult result = null ;
        List<?> hits = null ;
        try {
            result = getClientConfig("http://127.0.0.1:9200/myindex").execute(search);
            System.out.println("本次查询共查到："+result.getTotal()+"个关键字！");
            log.info("本次查询共查到："+result.getTotal()+"个关键字！");
            hits = result.getHits(o.getClass());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (List<Hit<T, Void>>) hits ;
    }

    public JsonArray createSearch(String keyWord , String type , Object o , String... fields) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        String ids[] = new String[]{"2268,2270"};
        String startTime = null;
        String endTime = "2017-08-29T09:06:01.000+08:00";
        if (keyWord != null && keyWord != "")
            searchSourceBuilder.query(QueryBuilders.termQuery("policestationId",ids)).
                    query(QueryBuilders.termQuery("name",keyWord)).
        query(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("createTime").from(startTime).to(endTime).includeLower(true).includeUpper(true))).
                    aggregation(AggregationBuilders.cardinality("agg1").field("alarmNo")).size(100);
        else{
            searchSourceBuilder.
                    query(QueryBuilders.matchAllQuery()).
                    query(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("createTime").from(startTime).to(endTime).includeLower(true).includeUpper(true))).
                    aggregation(AggregationBuilders.terms("alarmNo")).size(100);
        }
       /* HighlightBuilder highlightBuilder = new HighlightBuilder();
        for(String field : fields){
            highlightBuilder.field(field);//高亮field
        }*/
        /*highlightBuilder.preTags("<em>").postTags("</em>");//高亮标签
        highlightBuilder.fragmentSize(200);//高亮内容长度
        searchSourceBuilder.highlighter(highlightBuilder);*/
        Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex("myindex").addType("mytype").build();

        SearchResult result = null ;
        //List<?> hits = null ;
        JsonObject jsonObject = null;
        JsonArray hitsArray = null;
        try {
            result =getClientConfig("http://127.0.0.1:9200/").execute(search);
            System.out.println("本次查询共查到："+result.getTotal()+"个结果！");

            jsonObject = result.getJsonObject();
            JsonObject hitsObject = jsonObject.getAsJsonObject("hits");
             hitsArray = hitsObject.getAsJsonArray("hits");
           // System.out.println(hitsArray+"11111111111");
            for (int i = 0; i <hitsArray.size()-1 ; i++) {

                String alarmNo1 = hitsArray.get(i).getAsJsonObject().getAsJsonObject("_source").getAsJsonObject().get("alarmNo").toString();
                for (int j = i+1; j < hitsArray.size(); j++) {
                    String alarmNo2 = hitsArray.get(j).getAsJsonObject().getAsJsonObject("_source").getAsJsonObject().get("alarmNo").toString();
                    if (alarmNo2 != null && alarmNo2 != "") {
                        if (alarmNo1.equals(alarmNo2)) {
                            hitsArray.remove(i);
                            i--;
                            break;

                        }
                    }else{
                        continue;
                    }

                }
            }
            if (hitsArray.size() >10){
                System.out.println(hitsArray.size());
                for (int i = 10; i < hitsArray.size(); i++) {
                    hitsArray.remove(i);
                    i--;
                }
            }

            System.out.println(hitsArray);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return hitsArray;
    }
    public JestClient getClientConfig(String esUrl){
        JestClientFactory factory = new JestClientFactory();
        factory.setHttpClientConfig(new HttpClientConfig
                .Builder(esUrl)
                .gson(new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create())
                .multiThreaded(true)
                .readTimeout(100000)
                .build());
        JestClient client = factory.getObject();
        return client ;
    }

    public <T> void bulkIndex(String index, String type , T o) {
        Bulk bulk = new Bulk.Builder()
                .defaultIndex(index)
                .defaultType(type)
                .addAction(Arrays.asList(
                        new Index.Builder(o).build()
                )).build();
        try {
            esConfig.getClient().execute(bulk);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public <T> JestResult createIndex(T o, String index, String type) {
        Index index1 = new Index.Builder(o).index(index).type(type).build();
        JestResult jestResult = null ;
        try {
            jestResult = esConfig.getClient().execute(index1);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jestResult;
    }

    public JsonObject searchEvent(String param) {
        JsonObject returnData = new JsonParser().parse(param).getAsJsonObject();
        Search search = new Search.Builder(returnData.toString()).addType("event").addIndex("pi").build();

//      Gson gs = new Gson();
//      System.out.println("输入参数为：" + "\n" + gs.toJson(search));

        SearchResult result = null ;
        try {
            result = esConfig.getClient().execute(search);
//          System.out.println("\n" + gs.toJson(result.getJsonObject()) + "\n" );
//          System.out.println("本次查询共查到：" + "\n" +result.getTotal()+"个结果！");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.getJsonObject();
    }

    public JsonObject createSearch1(String keyWord , String type , Object o , String... fields) throws Exception {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        SearchSourceBuilder searchSourceBuilder1 = new SearchSourceBuilder();
        String ids[] = new String[]{"1221"};
        // String startTime = "";

        String startTime = "";
        String endTime = "";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'");
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));//时区定义并进行时间获取
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (startTime !=null && startTime != ""){
            startTime = sdf.format(sd.parse(startTime));  //将开始时间转换为utc时间(es中存储时间为utc时间)
            if (endTime !=null && endTime !=""){
                endTime = sdf.format(sd.parse(endTime));//将开始时间转换为utc时间(es中存储时间为utc时间)
            }else{   //有开始时间没有结束时间，结束时间默认为当前时间
                endTime = sdf.format(new Date());
            }
        }else{ //没有开始时间，结束时间有，那么需要转换，若结束时间没有，不用转换为当前时间
            if (endTime !=null && endTime !=""){
                endTime = sdf.format(sd.parse(endTime));
            }
        }
        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("policestationid", ids);//权限的机构id一定不为空
        if (keyWord != null && keyWord != "") { //有查询条件输入
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyWord, "name", "requestnum", "cert_no", "cphm");
           if ((startTime != null && startTime != "") || (endTime != null && endTime != "")){//有时间输入
               RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("createtime").from(startTime).to(endTime);
               searchSourceBuilder.query(QueryBuilders.boolQuery().must(multiMatchQueryBuilder).must(termsQueryBuilder).must(rangeQueryBuilder)).collapse(new CollapseBuilder("alarmno")).from(0).size(5);/*.aggregation(AggregationBuilders.cardinality("sum").field("id"))*/
               searchSourceBuilder1.query(QueryBuilders.boolQuery().must(multiMatchQueryBuilder).must(termsQueryBuilder).must(rangeQueryBuilder)).aggregation(AggregationBuilders.cardinality("count_alarmno").field("alarmno")).size(0);
           }else{ //没有时间输入
               searchSourceBuilder.query(QueryBuilders.boolQuery().must(multiMatchQueryBuilder).must(termsQueryBuilder)).collapse(new CollapseBuilder("alarmno")).from(0).size(5);/*.aggregation(AggregationBuilders.cardinality("sum").field("id"))*/
               searchSourceBuilder1.query(QueryBuilders.boolQuery().must(multiMatchQueryBuilder).must(termsQueryBuilder)).aggregation(AggregationBuilders.cardinality("count_alarmno").field("alarmno")).size(0);
           }

        }else{ //没有查询条件输入
            if ((startTime != null && startTime != "") || (endTime != null && endTime != "")){//有时间输入
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("createtime").from(startTime).to(endTime);
                searchSourceBuilder.query(QueryBuilders.boolQuery().must(termsQueryBuilder).must(rangeQueryBuilder)).collapse(new CollapseBuilder("alarmno")).from(0).size(5);/*.aggregation(AggregationBuilders.cardinality("sum").field("id"))*/
                searchSourceBuilder1.query(QueryBuilders.boolQuery().must(termsQueryBuilder).must(rangeQueryBuilder)).aggregation(AggregationBuilders.cardinality("count_alarmno").field("alarmno")).size(0);
            }else{ //没有时间输入
                searchSourceBuilder.query(QueryBuilders.boolQuery().must(termsQueryBuilder)).collapse(new CollapseBuilder("alarmno")).from(0).size(5);/*.aggregation(AggregationBuilders.cardinality("sum").field("id"))*/
                searchSourceBuilder1.query(QueryBuilders.boolQuery().must(termsQueryBuilder)).aggregation(AggregationBuilders.cardinality("count_alarmno").field("alarmno")).size(0);

            }
        }






                   // query(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("createTime").from(startTime).to(endTime).includeLower(true).includeUpper(true))).
                  //  aggregation(AggregationBuilders.cardinality(keyWord).field("alarmNo.raw")).size(10);
       /* else {
            searchSourceBuilder.
                    query(QueryBuilders.matchAllQuery()).
                    query(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("createTime").from(startTime).to(endTime).includeLower(true).includeUpper(true))).
                    aggregation(AggregationBuilders.terms("alarmNo")).size(100);
        }*/
       /* HighlightBuilder highlightBuilder = new HighlightBuilder();
        for(String field : fields){
            highlightBuilder.field(field);//高亮field
        }*/
        /*highlightBuilder.preTags("<em>").postTags("</em>");//高亮标签
        highlightBuilder.fragmentSize(200);//高亮内容长度
        searchSourceBuilder.highlighter(highlightBuilder);*/
        Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex("myindex").addType("mytype").build();
        Search search1 = new Search.Builder(searchSourceBuilder1.toString()).addIndex("myindex").addType("mytype").build();
        System.out.println(searchSourceBuilder);
        System.out.println(searchSourceBuilder1);
        SearchResult result = null;
        //List<?> hits = null ;
        JsonObject jsonObject = null;
        JsonArray hitsArray = null;
        try {

            result = getClientConfig("http://127.0.0.1:9200/").execute(search);
            System.out.println("折叠alarmno后：\n"+result.getJsonString());
            result = getClientConfig("http://127.0.0.1:9200/").execute(search1);
            System.out.println("折叠alarmno后数量：\n"+result.getJsonString());

            jsonObject = result.getJsonObject();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }
}
